package adapter

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/opensourceways/server-common-lib/utils"

	"cvevulner/cve-ddd/app"
	"cvevulner/cve-ddd/infrastructure/bulletinimpl"
	"cvevulner/cve-ddd/infrastructure/obsimpl"
	"cvevulner/cve-ddd/infrastructure/repositoryimpl"
	"cvevulner/cve-ddd/infrastructure/updateinfoimpl"
	"cvevulner/util"
)

const hotPatchIssue = "https://gitee.com/api/v5/repos/openeuler/hotpatch_meta/issues?" +
	"access_token=%s&state=closed&labels=%s&sort=created&direction=desc&page=%d&per_page=20&created_at=%s"

var (
	RegexpCve  = regexp.MustCompile(`<id>(?s:(.*?))</id>`)
	RegexpRPM  = regexp.MustCompile(`热补丁路径[:：](?s:(.*?))热补丁信息[:：]`)
	RegexpMeta = regexp.MustCompile(`热补丁元数据[:：](?s:(.*?))热补丁路径[:：]`)
	RegexpType = regexp.MustCompile(`问题类别[:：](?s:(.*?))热补丁元数据[:：]`)
	RegexpInfo = regexp.MustCompile(`热补丁信息[:：](?s:(.*?))$`)
)

func NewHotPatchAdapter() *hotPatch {
	return &hotPatch{
		service: app.NewHotPatchService(
			repositoryimpl.NewRepositoryImpl(),
			bulletinimpl.NewBulletinImpl(),
			obsimpl.Instance(),
			updateinfoimpl.NewUpdateInfoImpl(),
		),
	}
}

type hotPatch struct {
	service app.HotPatchService
}

type patchIssue = app.CmdToGenerateBulletins

type Issue struct {
	Number string `json:"number"`
	Body   string `json:"body"`
}

func (h *hotPatch) Process() {
	issues, err := h.getIssues()
	if err != nil {
		logs.Error("get hot patch issue error: %s", err.Error())

		return
	}

	var patches []patchIssue
	for _, v := range issues {
		pat, err := h.toPatchIssue(v.Body)
		if err != nil {
			logs.Error("issue number %s toPatchIssue error: %s", v.Number, err.Error())
			continue
		}
		pat.HotIssueNum = v.Number

		patches = append(patches, pat)
	}

	if err := h.service.GenerateBulletins(patches); err != nil {
		logs.Error("generate bulletins error %s", err.Error())
	}

}

func (h *hotPatch) getIssues() ([]Issue, error) {
	var page = 1
	var issues []Issue
	token := beego.AppConfig.String("gitee::git_token")
	cli := utils.NewHttpClient(3)
	// query the data of the last 15 days
	filterCreatedTime := time.Now().AddDate(0, 0, -15).Format("20060102T1504015-")

	for {
		url := fmt.Sprintf(hotPatchIssue, token, "hotpatch", page, filterCreatedTime)
		req, err := http.NewRequest(
			http.MethodGet, url, nil,
		)
		if err != nil {
			return nil, err
		}

		res, _, err := cli.Download(req)
		if err != nil {
			return nil, err
		}

		var t []Issue
		if err := json.Unmarshal(res, &t); err != nil {
			return nil, err
		}

		if len(t) == 0 {
			break
		}

		issues = append(issues, t...)

		page++
	}

	return issues, nil
}

func (h *hotPatch) toPatchIssue(body string) (v patchIssue, err error) {
	t := RegexpType.FindAllStringSubmatch(body, -1)
	if len(t) == 0 {
		return v, errors.New("parse type failed")
	}
	v.Type = strings.TrimSpace(t[0][1])

	meta := RegexpMeta.FindAllStringSubmatch(body, -1)
	if len(meta) == 0 {
		return v, errors.New("parse metadata failed")
	}
	split := strings.Split(meta[0][1], "/")
	v.Branch = split[len(split)-4]
	v.Component = split[len(split)-3]

	p := RegexpRPM.FindAllStringSubmatch(body, -1)
	if len(p) == 0 {
		return v, errors.New("parse rpm failed")
	}
	v.PatchUrl = strings.Split(strings.TrimSpace(p[0][1]), "\n")

	info := RegexpInfo.FindAllStringSubmatch(body, -1)
	if len(info) == 0 {
		return v, errors.New("parse info failed")
	}
	var bys []byte
	for _, s := range strings.Split(strings.TrimSpace(info[0][1]), "\n") {
		bys, err = util.HTTPGetCom(strings.TrimSpace(s))
		if err != nil {
			continue
		}

		if cve := RegexpCve.FindAllStringSubmatch(string(bys), -1); len(cve) > 0 {
			v.CveNum = strings.Split(cve[0][1], ",")
			break
		}
	}

	if len(v.CveNum) == 0 {
		return v, errors.New("parse cve num failed")
	}

	return
}
